package org.magnerfuller.imtoolkit.server.connection.manager;

import java.util.Vector;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.magnerfuller.imtoolkit.server.connection.handler.ConnectionHandler;
import org.magnerfuller.imtoolkit.server.connection.event.listener.ConnectionListener;
import org.magnerfuller.imtoolkit.server.connection.event.ConnectionEvent;
import org.magnerfuller.imtoolkit.server.connection.manager.event.ConnectionManagerEvent;
import org.magnerfuller.imtoolkit.server.connection.manager.event.listener.ConnectionManagerListener;
import org.magnerfuller.imtoolkit.server.service.ServiceDescription;
import org.magnerfuller.imtoolkit.server.session.Session;
import org.magnerfuller.imtoolkit.server.session.SessionFactory;
import org.magnerfuller.imtoolkit.server.session.medium.SessionDescription;

/**
 * 
 * Class ConnectionManager
 * 
 * Objects of this class manage ConnectionHandler objects.
 *
 */
public class ConnectionManager implements ConnectionListener {

  /** connectionHandlers -- These are the connection handlers. */
  private Vector<ConnectionHandler> connectionHandlers;
  
  /** connectionHandlersLock -- Synchronize access to the connnectionHandlers. */
  private final Lock connectionHandlersLock = new  ReentrantLock();

  /** connectionManagerListeners -- The Manager delivers events to these. */
  private Vector<ConnectionManagerListener> connectionManagerListeners;
  
  /** connectionManagerListenersLock -- Synchronize access to the listeners. */
  private final Lock connectionManagerListenersLock = new ReentrantLock();

  /**
   * Constructor
   *
   */
  public ConnectionManager() {
    connectionHandlers = new Vector<ConnectionHandler>();
    connectionManagerListeners = new Vector<ConnectionManagerListener>();
  }//ConnectionManager

  /**
   * Add a ConnectionManagerListener to this connection manager.
   * Connection managers listeners are notified of events occurring in
   * the connection manager.
   * 
   * @param l the listener to register
   *
   */
  public void addConnectionManagerListener(ConnectionManagerListener l) {
    connectionManagerListenersLock.lock();
    try {
      connectionManagerListeners.add(l);
    } finally {
      connectionManagerListenersLock.unlock();
    }
  }//addConnectionManagerListener

  /**
   * Remove a ConnectionManagerListener from this connection manager.
   *
   * @param l the listener to remove
   *
   */
  public boolean removeConnectionManagerListener(ConnectionManagerListener l) {
    boolean removed = false;
    connectionManagerListenersLock.lock();
    try {
      removed = connectionManagerListeners.remove(l);
    } finally {
      connectionManagerListenersLock.unlock();
    }
    return removed;
  }//removeConnectionManagerListener

  /**
   * Add a ConnectionHandler to manage and register as its listener.
   *
   * @param handler the handler to register
   *
   */
  public void addConnectionHandler(ConnectionHandler handler) {
    connectionHandlersLock.lock();
    try {
      connectionHandlers.add(handler);
      handler.addConnectionListener(this);
    } finally {
      connectionHandlersLock.unlock();
    }
  }//addConnectionHandler

  /**
   * Manage a ConnectionHandler object.
   * 
   * @param handler
   */
  public void manageConnection(ConnectionHandler handler) {
    addConnectionHandler(handler);
    handler.start();
  }//manageConnection
  
  /**
   * Remove a ConnectionHandler and deregister as a listener.
   * 
   * @param handler the handler to deregister
   *
   */
  public boolean removeConnectionHandler(ConnectionHandler handler) {
    boolean removed = false;
    connectionHandlersLock.lock();
    try {
      handler.removeConnectionListener(this);
      removed = connectionHandlers.remove(handler);
    } finally {
      connectionHandlersLock.unlock();
    }
    
    return removed;
  }//removeConnectionHandler

  /**
   * Handle a ConnectionEvent.
   *
   * @param e the event
   *
   */
  public void connectionOccurred(ConnectionEvent e) {
    SessionDescription sessionDesc = e.getSessionDescription();
    ServiceDescription serviceDesc = e.getSource().getServiceDescription();
    
    Session session = SessionFactory.getInstance().createSession(serviceDesc, sessionDesc);
    
    if(session == null) {
      System.err.println("Session is null!");
    }
    if(sessionDesc == null) {
      System.err.println("sessionDesc is null!");
    }
    if(serviceDesc == null) {
      System.err.println("serviceDesc is null!");
    }
    
    ConnectionManagerEvent event = new ConnectionManagerEvent(this, session);
    _fireConnectionManagerEvent(event);
  }//connectionOccurred

  /**
   * Fire a ConnectionManagerEvent to all listeners.
   *
   * @param e the event
   *
   */
  public void _fireConnectionManagerEvent(ConnectionManagerEvent e) {
    connectionManagerListenersLock.lock();
    try {
      for(ConnectionManagerListener l : connectionManagerListeners) {
        l.connectionManagerEventOccurred(e);
      }
    } finally {
      connectionManagerListenersLock.unlock();
    }
  }//_fireConnectionManagerEvent

}//ConnectionManager
